﻿using MIO.Client.Protocal;
using MIO.Client.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace MIO.Client.Daemon
{
    public class KeepAliveDaemon
    {
        private const String TAG = nameof(KeepAliveDaemon);

        public static int NETWORK_CONNECTION_TIME_OUT = 10 * 1000;
        public static int KEEP_ALIVE_INTERVAL = 3000;//1000;

        private bool keepAliveRunning = false;
        private long lastGetKeepAliveResponseFromServerTimstamp = 0;
        private readonly object lastGetKeepAliveResponseFromServerTimstampLock = new object();
        private bool _excuting = false;
        private Timer timer = null;
        public IOClient Client { get; private set; }

        public long LastGetKeepAliveResponseFromServerTimstamp
        {
            get
            {
                lock (lastGetKeepAliveResponseFromServerTimstampLock)
                    return lastGetKeepAliveResponseFromServerTimstamp;
            }

            private set
            {
                lock (lastGetKeepAliveResponseFromServerTimstampLock)
                    lastGetKeepAliveResponseFromServerTimstamp = value;
            }
        }

        public event EventHandler LostKeepAlive_Event = null;

        public KeepAliveDaemon(IOClient client)
        {
            this.Client = client;
            init();
        }

        private void init()
        {
            timer = new Timer(KEEP_ALIVE_INTERVAL);
            timer.Elapsed += (sender, e) =>
            {
                run();
            };
        }

        private Packet createKeepAlivePacket()
        {
            Packet packet = new Packet()
            {
                Type = PacketType.KEEP_ALIVE,
                SessionId = "",
                DataContent = "",
                Ack = false,
                AckId = "",
            };
            return packet;
        }

        public void run()
        {
            if (!_excuting)
            {
                bool willStop = false;
                _excuting = true;
                bool sendSuccess = Client.send(createKeepAlivePacket());

                bool isInitialedForKeepAlive = (LastGetKeepAliveResponseFromServerTimstamp == 0);
                if (sendSuccess && LastGetKeepAliveResponseFromServerTimstamp == 0)
                    LastGetKeepAliveResponseFromServerTimstamp = DateUtil.GetCurrentTimeStamp();

                if (!isInitialedForKeepAlive)
                {
                    long now = DateUtil.GetCurrentTimeStamp();
                    if (now - LastGetKeepAliveResponseFromServerTimstamp >= NETWORK_CONNECTION_TIME_OUT)
                    {
                        stop();
                        willStop = true;
                    }
                }
                _excuting = false;
                if (willStop)
                {
                    timer.Stop();
                    LostKeepAlive_Event?.Invoke(this, EventArgs.Empty);
                }
            }
        }

        public void stop()
        {
            if (timer != null)
                timer.Stop();
            keepAliveRunning = false;
            _excuting = false;
            LastGetKeepAliveResponseFromServerTimstamp = 0;
        }

        public void start(bool immediately)
        {
            stop();

            if (immediately)
                timer.Interval = 1;
            else
                timer.Interval = KEEP_ALIVE_INTERVAL;
            timer.Start();
            Client?.send(createKeepAlivePacket());
            keepAliveRunning = true;
        }

        public bool isKeepAliveRunning()
        {
            return keepAliveRunning;
        }

        public void updateGetKeepAliveResponseFromServerTimstamp()
        {
            LastGetKeepAliveResponseFromServerTimstamp = DateUtil.GetCurrentTimeStamp();
        }
    }
}
